home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
- static char rcsid[] = "$Header: ins2.c,v 2.4 84/10/26 12:08:24 guido Exp $";
-
- /*
- * B editor -- Insert characters from keyboard.
- */
-
- #include "b.h"
- #include "bobj.h"
- #include "node.h"
- #include "supr.h"
- #include "queu.h"
- #include "gram.h"
- #include "tabl.h"
-
-
- /*
- * Insert a character.
- */
-
- Visible bool
- ins_char(ep, c, alt_c)
- register environ *ep;
- int c;
- int alt_c;
- {
- auto queue q = Qnil;
- auto queue qf = Qnil;
- auto value copyout();
- auto string str;
- char buf[2];
- int where;
- bool spwhere;
-
- higher(ep);
- shrink(ep);
- if (index("({[`'\"", c) && !ishole(ep)) {
- /* Surround something. Wonder what will happen! */
- qf = (queue) copyout(ep);
- if (!delbody(ep)) {
- qrelease(qf);
- return No;
- }
- }
- fixit(ep);
- ep->changed = Yes;
- buf[0] = c;
- buf[1] = 0;
- if (!ins_string(ep, buf, &q, alt_c))
- return No;
- if (!emptyqueue(q) || !emptyqueue(qf)) {
- /* Slight variation on app_queue */
- if (!emptyqueue(qf) && emptyqueue(q))
- ritevhole(ep); /* Wizardry. Why does this work? */
- spwhere = ep->spflag;
- ep->spflag = No;
- where = focoffset(ep);
- markpath(&ep->focus, 1);
- ep->spflag = spwhere;
- if (ep->mode == FHOLE && ep->s2 > 0) {
- /* If we just caused a suggestion, insert the remains
- after the suggested text, not after its first character. */
- str = "";
- if (!soften(ep, &str, 0)) {
- ep->mode = ATEND;
- leftvhole(ep);
- if (symbol(tree(ep->focus)) == Hole) {
- ep->mode = ATBEGIN;
- leftvhole(ep);
- }
- }
- }
- if (!emptyqueue(q)) { /* Re-insert stuff queued by ins_string */
- if (!ins_queue(ep, &q, &q))
- return No;
- where += spwhere;
- spwhere = No;
- }
- if (!emptyqueue(qf)) { /* Re-insert deleted old focus */
- firstmarked(&ep->focus, 1) || Abort();
- fixfocus(ep, where);
- if (!ins_queue(ep, &qf, &qf))
- return No;
- }
- firstmarked(&ep->focus, 1) || Abort();
- unmkpath(&ep->focus, 1);
- ep->spflag = No;
- fixfocus(ep, where + spwhere);
- }
- return Yes;
- }
-
-
- /*
- * Insert a newline.
- */
-
- Visible bool
- ins_newline(ep)
- register environ *ep;
- {
- register node n;
- register int sym;
- auto bool mayindent;
-
- ep->changed = Yes;
- if (!fiddle(ep, &mayindent))
- return No;
- for (;;) {
- switch (ep->mode) {
-
- case VHOLE:
- ep->mode = ATEND;
- continue;
-
- case FHOLE:
- ep->s2 = lenitem(ep);
- if (!fix_move(ep))
- return No;
- continue;
-
- case ATEND:
- if (!joinstring(&ep->focus, "\n", No, 0, mayindent)) {
- if (!move_on(ep))
- return No;
- continue;
- }
- s_downi(ep, 2);
- s_downi(ep, 1);
- ep->mode = WHOLE;
- Assert((sym = symbol(tree(ep->focus))) == Hole || sym == Optional);
- return Yes;
-
- case ATBEGIN:
- n = tree(ep->focus);
- if (Type(n) == Tex) {
- ep->mode = ATEND;
- continue;
- }
- sym = symbol(n);
- if (sym == Hole || sym == Optional) {
- ep->mode = WHOLE;
- continue;
- }
- n = nodecopy(n);
- if (!fitstring(&ep->focus, "\n", 0)) {
- if (!down(&ep->focus))
- ep->mode = ATEND;
- noderelease(n);
- continue;
- }
- s_downrite(ep);
- if (fitnode(&ep->focus, n)) {
- noderelease(n);
- s_up(ep);
- s_down(ep);
- ep->mode = WHOLE;
- return Yes;
- }
- s_up(ep);
- s_down(ep);
- if (!fitnode(&ep->focus, n)) {
- noderelease(n);
- #ifndef NDEBUG
- debug("[Sorry, I don't see how to insert a newline here]");
- #endif NDEBUG
- return No;
- }
- noderelease(n);
- ep->mode = ATBEGIN;
- return Yes;
-
- case WHOLE:
- Assert((sym = symbol(tree(ep->focus))) == Hole || sym == Optional);
- if (!fitstring(&ep->focus, "\n", 0)) {
- ep->mode = ATEND;
- continue;
- }
- s_downi(ep, 1);
- Assert((sym = symbol(tree(ep->focus))) == Hole || sym == Optional);
- ep->mode = WHOLE;
- return Yes;
-
- default:
- Abort();
-
- }
- }
- }
-
-
- /*
- * Refinement for ins_newline() to do the initial processing.
- */
-
- Hidden bool
- fiddle(ep, pmayindent)
- register environ *ep;
- bool *pmayindent;
- {
- register int level;
- auto string str = "";
-
- higher(ep);
- while (rnarrow(ep))
- ;
- fixit(ep);
- soften(ep, &str, 0);
- higher(ep);
- *pmayindent = Yes;
- if (atdedent(ep)) {
- *pmayindent = No;
- s_up(ep);
- level = Level(ep->focus);
- delfocus(&ep->focus);
- if (symbol(tree(ep->focus)) == Hole) {
- if (hackhack(ep))
- return Yes;
- }
- while (Level(ep->focus) >= level) {
- if (!nexthole(ep)) {
- ep->mode = ATEND;
- break;
- }
- }
- if (ep->mode == ATEND) {
- leftvhole(ep);
- ep->mode = ATEND;
- while (Level(ep->focus) >= level) {
- if (!up(&ep->focus))
- return No;
- }
- }
- return Yes;
- }
- return Yes;
- }
-
-
- /*
- * "Hier komen de houthakkers."
- *
- * Incredibly ugly hack to delete a join whose second child begins with \n,
- * such as a suite after an IF, FOR or WHILE or unit heading.
- * Inspects the parent node.
- * If this has rp[0] ands rp[1] both empty, replace it by its first child.
- * (caller assures this makes sense).
- * Return Yes if this happened AND rp[1] contained a \t.
- */
-
- Hidden Procedure
- hackhack(ep)
- environ *ep;
- {
- node n;
- int ich = ichild(ep->focus);
- string *rp;
-
- if (!up(&ep->focus))
- return No;
- higher(ep);
- rp = noderepr(tree(ep->focus));
- if (!Fw_zero(rp[0]) || !Fw_zero(rp[1])) {
- s_downi(ep, ich);
- return No;
- }
- n = nodecopy(firstchild(tree(ep->focus)));
- delfocus(&ep->focus);
- replace(&ep->focus, n);
- ep->mode = ATEND;
- return rp[1] && rp[1][0] == '\t';
- }
-
-
- /*
- * Refinement for fiddle() to find out whether we are at a possible
- * decrease-indentation position.
- */
-
- Hidden bool
- atdedent(ep)
- register environ *ep;
- {
- register path pa;
- register node npa;
- register int i;
- register int sym = symbol(tree(ep->focus));
-
- if (sym != Hole && sym != Optional)
- return No;
- if (ichild(ep->focus) != 1)
- return No;
- switch (ep->mode) {
- case FHOLE:
- if (ep->s1 != 1 || ep->s2 != 0)
- return No;
- break;
- case ATBEGIN:
- case WHOLE:
- case SUBSET:
- break;
- default:
- return No;
- }
- pa = parent(ep->focus);
- if (!pa)
- return No;
- npa = tree(pa);
- if (fwidth(noderepr(npa)[0]) >= 0)
- return No;
- for (i = nchildren(npa); i > 1; --i) {
- sym = symbol(child(npa, i));
- if (sym != Hole && sym != Optional)
- return No;
- }
- return Yes; /* Sigh! */
- }
-
- /*
- * Refinement for ins_node() and fiddle() to find the next hole,
- * skipping blank space only.
- */
-
- Hidden bool
- nexthole(ep)
- register environ *ep;
- {
- register node n;
- register int ich;
- register string repr;
-
- do {
- ich = ichild(ep->focus);
- if (!up(&ep->focus))
- return No;
- higher(ep);
- n = tree(ep->focus);
- repr = noderepr(n)[ich];
- if (!Fw_zero(repr) && !allspaces(repr))
- return No;
- } while (ich >= nchildren(n));
- s_downi(ep, ich+1);
- return Yes;
- }
-